// // 自己实现一个myBox
// struct MyBox<T>(T);

// impl<T> MyBox<T> {
//     fn new(x: T) -> MyBox<T> {
//         MyBox(x)
//     }
// }

// // 实现Deref trait
// use std::ops::Deref;
// // T表示MyBox的泛型
// impl<T> Deref for MyBox<T> {
//     type Target = T;

//     // 实现deref方法
//     fn deref(&self) -> &T {
//         &self.0 // .0表示MyBox的泛型T
//     }
// }
use std::ops::Deref;
struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}

impl<T> Deref for MyBox<T>{
    type Target = T;
    fn deref(&self) -> &T {
        &self.0
    }
}

fn main() {
    let s = 5;
    // let c = &s;
    // 使用Box来替换
    let c = Box::new(s);
    assert_eq!(5, s);
    assert_eq!(5, *c);

    // 使用自己实现的MyBox
    let s1 = 5;
    let c1 = MyBox::new(s1);
    assert_eq!(5, s1);
    // 此时报错, 因为我们的MyBox没有实现Deref trait, 所以不能解引用
    // 实现了deref这个trait之后, 就可以解引用了
    assert_eq!(5, *c1);
    // *c1其实就相当于以下代码, 即, 调用了MyBox的deref方法
    let cc = *(c1.deref());
    assert_eq!(5, cc);

    // 15.2内容, 当参数类型不匹配的时候,
    // 可以使用Deref coercion, rust会自动调用deref方法
    fn hello(str: &str) {
        println!("this is : {}", str);
    }

    let params = MyBox::new(String::from("hello"));
    // 转换过程如下:
    let string_type = params.deref();
    let str_type = string_type.deref();
    // params原本是MyBox<String>, 但是hello函数的参数是&str, 所以rust会自动调用params的deref方法
    // 将MyBox<String>转换为&String, 而String实现了Deref trait, 所以可以自动转换为&str
    hello(&params)
    // 转换规则:
    // T: Deref<Target=U>, 允许&T自动转换为&U
    // T: DerefMut<Target=U>, 允许&mut T自动转换为&mut U
    // T: Deref<Target=U>, 允许&mut T自动转换为&U
    // 这些规则的内在逻辑是: &U是&mut U的子集, 所以&mut T可以转换为&U, 但是&U不能转换为&mut U
}
